package com.piece.mall.service;

import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.exception.ServerException;
import com.piece.core.framework.support.bootstrap.DataTable;
import com.piece.core.framework.support.bootstrap.QueryTable;
import com.piece.core.framework.util.collection.MapUtil;
import com.piece.core.framework.util.lock.ZLock;
import com.piece.core.jpa.repository.BaseService;
import com.piece.core.redis.lock.RedissonDistributedLock;
import com.piece.mall.api.enums.OrderStatusType;
import com.piece.mall.model.OmsOrder;
import com.piece.mall.model.WmsWareOrderTaskDetail;
import com.piece.mall.model.WmsWareSku;
import com.piece.mall.repository.WmsWareSkuRepository;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class WmsWareSkuService extends BaseService<WmsWareSku, String> {

    @Resource
    private RedissonDistributedLock redissonDistributedLock;

    @Autowired
    private WmsWareSkuRepository wmsWareSkuRepository;

    @Resource
    private WmsWareOrderTaskDetailService wmsWareOrderTaskDetailService;

    @PostConstruct
    public void initRepository() {
        setRepository(wmsWareSkuRepository);
    }

    public DataTable findPage(QueryTable queryTable) {
        String hql = "select s.*, i.name as wareName from `wms_ware_sku` s " +
                " left join `wms_ware_info` i on s.ware_id = i.id ";
        queryTable.setAlias("s");
        queryTable.setHql(hql);
        return wmsWareSkuRepository.findPageBySql(queryTable);
    }

    /**
     * 查询商品库存
     */
    public Long findSkuStock(Long skuId) {
        WmsWareSku wareSku = wmsWareSkuRepository.findOneByCondition(MapUtil.builder(new HashMap<String, Object>())
                .put("Q_skuId_L_EQ", skuId).build());
        return (null == wareSku || null == wareSku.getStock()) ? 0L : wareSku.getStock();
    }

    /**
     * 查询商品库存
     */
    public Map<Long, Long> findSkuStocks(List<Long> skuIds) {
        Map<Long, Long> result = new HashMap<>();
        List<WmsWareSku> wareSkus = wmsWareSkuRepository.findByCondition(MapUtil.builder(new HashMap<String, Object>())
                .put("Q_skuId_L_IN", skuIds).build(), null);
        wareSkus.stream().forEach(wareSku -> {
            result.put(wareSku.getSkuId(), null == wareSku.getStock() ? 0L : wareSku.getStock());
        });
        return result;
    }

    /**
     * 删除商品库存
     */
    public void deleteSkuStock(List<Long> skuIds) {
        wmsWareSkuRepository.executeSql("delete from `wms_ware_sku` s where s.sku_id in (?0)", new Object[]{ skuIds });
    }

    /**
     * 锁定商品库存
     *
     * @param orderSn 订单号
     * @param skuId   skuId
     * @param count   锁定数量
     */
    public void lockStock(String orderSn, Long skuId, Integer count) {
        ZLock lock = redissonDistributedLock.lock(skuId + "", true);
        try {
            // 查询所有仓库
            List<WmsWareSku> wareSkus = wmsWareSkuRepository.findByCondition("skuId", skuId, null);
            if (CollectionUtils.isEmpty(wareSkus)) {
                throw new ServerException("仓库中未找到商品[" + skuId + "]!");
            }
            // 查询锁定库存
            Boolean skuStocked = false;
            String sql = "update wms_ware_sku set stock_locked = (stock_locked + ?0) where sku_id = ?1 and ware_id = ?2 " +
                    "and (stock - stock_locked) >= ?3";
            for (WmsWareSku wareSku : wareSkus) {
                Integer num = wmsWareSkuRepository.executeSql(sql, new Object[]{count, skuId, wareSku.getWareId(), count});
                if (1 == num) {
                    // 锁定成功
                    skuStocked = true;
                    // 创建库存锁定工作单详情
                    WmsWareOrderTaskDetail taskDetail = new WmsWareOrderTaskDetail();
                    taskDetail.setOrderSn(orderSn);
                    taskDetail.setSkuId(wareSku.getSkuId());
                    taskDetail.setWareId(wareSku.getWareId());
                    taskDetail.setLockNum(count);
                    wmsWareOrderTaskDetailService.insert(taskDetail);
                    break;
                }
            }
            if (!skuStocked) {
                throw new ServerException("商品[" + skuId + "]库存不足!");
            }

            // 发送库存锁定消息 TODO

        } catch (Exception e) {
            throw new ServerException(e.getMessage());
        } finally {
            redissonDistributedLock.unlock(lock);
        }
    }

    /**
     * 解锁商品库存
     */
    public void unLockStock(OmsOrder order, Long skuId) {
        ZLock lock = redissonDistributedLock.lock(skuId + "", true);
        try {
            WmsWareOrderTaskDetail taskDetail = wmsWareOrderTaskDetailService.findOneByCondition(MapUtil.builder(new HashMap<String, Object>())
                    .put("orderSn", order.getOrderSn())
                    .put("skuId", skuId).build());

            if (null == taskDetail) {
                throw new ServerException(ExceptionConstants.NOT_EXIST, "订单商品[" + order.getOrderSn() + "]-" + skuId);
            }

            // 已取消,待付款,已付款 订单解锁库存
            OrderStatusType statusType = OrderStatusType.getByCode(order.getStatus());
            switch (statusType) {
                case PREPARE:
                case PAYED:
                case CANCEL:
                    String sql = "update wms_ware_sku set stock_locked = (stock_locked - ?0) where sku_id = ?1 and ware_id = ?2 ";
                    wmsWareSkuRepository.executeSql(sql, new Object[]{ taskDetail.getLockNum(), skuId, taskDetail.getWareId() });
                    break;
            }

        } catch (Exception e) {
            throw new ServerException(e.getMessage());
        } finally {
            redissonDistributedLock.unlock(lock);
        }
    }
}
